/******************************************************************
 * Created by: DO HOANG HAI                                       
 * Date of Creation: 15/sep/2007                                              
 * Date of last modification: 22nd/Dec/2007
 *                                                                
 * Description: Form for specifying search criteria.
 ******************************************************************/

using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Pbdms.DataAccess;
using Pbdms.BusinessLogic.DataController;
using Pbdms.BusinessLogic.Search;
using Pbdms.Common.DataObject;

namespace Pbdms.Forms.Tools
{
    public partial class FrmSearch : Form
    {
        public FrmSearch()
        {
            InitializeComponent();
            Pbdms.Common.Global.paintBackGround(this);
            mtbRating.Text = "0.0";
            loadCategories();
        }

        /// <summary>
        /// load categories available from database into the form
        /// </summary>
        private void loadCategories()
        {
            ArrayList arl;
            arl = CategoryController.create().getListOfCategories();
            ddlCategory.Items.Clear();
            ddlCategory.Items.Add("All");
            for (int i = 0; i < arl.Count; i++)
            {
                ddlCategory.Items.Add(arl[i].ToString());
            }
            
            ddlCategory.SelectedIndex = 0;
            rbLocal.Checked = true;
        }

        /// <summary>
        /// cancel the search, simple close the form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// fill the form with specified search object
        /// </summary>
        /// <param name="searchObject"></param>
        public void fillSearchCriteria(Common.DataObject.SearchObj searchObject)
        {
            //clear the content
            clearSearchCriteria();

            //fill all control with corresponding data from the search object
            //1. Source
            if (searchObject.SearchSource == Common.DataObject.ResultItem.ITEM_SOURCE_LOCAL)
                rbLocal.Checked = true;
            else if (searchObject.SearchSource == Common.DataObject.ResultItem.ITEM_SOURCE_NETWORK)
                rbNetwork.Checked = true;
            else
                rbBoth.Checked = true;
            //2. category            
            ddlCategory.SelectedIndex  = Common.Global.getDdlItemByStringValue(ddlCategory, searchObject.Category);
            //3. file info:
            if (searchObject.HasFile)
            {
                chkBHasFile.Checked = true;
                tbMinFileSize.Enabled = true;
                tbMaxFileSize.Enabled = true;
                tbMinFileSize.Text = searchObject.MinFileSize.ToString();
                tbMaxFileSize.Text = searchObject.MaxFileSize.ToString();
            }
            else
            {
                chkBHasFile.Checked = false;
                tbMinFileSize.Enabled = false;
                tbMaxFileSize.Enabled = false;
            }
            //4. comments
            chkBHasFile.Checked = searchObject.HasFile;
            mtbRating.Text = searchObject.MinRating.ToString();
            //5. tags:
            if (searchObject.Tags != null && searchObject.Tags.Count > 0)
            {
                foreach (object obj in searchObject.Tags)
                {
                    tbTag.Text = tbTag.Text + obj.ToString() + ", ";
                }
                tbTag.Text = tbTag.Text.Substring(0, tbTag.Text.Length - 2);
            }
            //6. bibtexes
            if (searchObject.BibTexesStruct != null && searchObject.BibTexesStruct.Count > 0)
            {
                int i = 1;
                foreach (object obj in searchObject.BibTexesStruct)
                {
                    ComboBox ddl = (ComboBox)(this.Controls.Find("ddl" + i, true)[0]);
                    TextBox tb = (TextBox)(this.Controls.Find("tb" + i, true)[0]);
                    Common.DataObject.BibTexStruct bts = (Common.DataObject.BibTexStruct)obj;
                    ddl.SelectedIndex = Common.Global.getDdlItemByStringValue(ddl,bts.name);
                    tb.Text = bts.value;
                    i++;
                }
            } 
        }

        /// <summary>
        /// start searching
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            //check the validity of inputs
            if (validateInput())
            {
                int searchSource;
                bool hasComment = chkbComment.Checked; ;
                double minRating = Double.Parse(normalizeMtbRating(mtbRating.Text));
                bool hasFile = chkBHasFile.Checked;

                string category = ddlCategory.SelectedItem.ToString();
                long minFileSize = 0;
                long maxFileSize = 100000000;

                ArrayList tags = readTag();
                ArrayList bibTexesStruct = readBibTexes();

                //search source
                if (rbLocal.Checked)
                    searchSource = SearchObj.SOURCE_LOCAL_ONLY;
                else if (rbNetwork.Checked)
                    searchSource = SearchObj.SOURCE_NETWORK_ONLY;
                else
                    searchSource = SearchObj.SOURCE_LOCAL_AND_NETWORK;

                //file's size
                if (hasFile)
                {
                    minFileSize = (long)((Math.Round(double.Parse(tbMinFileSize.Text)*1024)));
                    maxFileSize = (long)((Math.Round(double.Parse(tbMaxFileSize.Text)*1024)));
                }
                //construct the search ojbect.
                SearchObj searchObject = new SearchObj(searchSource, hasComment, minRating,
                    hasFile, tags, category, minFileSize, maxFileSize, bibTexesStruct);

                ////obtain the results from the library
                //((FrmMain)this.MdiParent).stStrLblTask.Text = "Searching...";
                //((FrmMain)this.MdiParent).stStrProgressBar.Visible = true;
                this.Cursor = Cursors.WaitCursor;

                ArrayList resultList = BusinessLogic.Search.SearchProcessor.create(searchObject, true, Program.networkCtrller).getResult();
                this.Cursor = Cursors.Default;
                //((FrmMain)this.MdiParent).stStrProgressBar.Visible = false;
                //((FrmMain)this.MdiParent).stStrLblTask.Text = "Ready";

                //show the result
                bool alreadyExisted = false;
                foreach (Form frm in (this.MdiParent.MdiChildren))
                {
                    frm.WindowState = FormWindowState.Normal;
                    if (frm.GetType().Equals(typeof(Pbdms.Forms.Views.FrmSearchResult)))
                    {
                        ((Pbdms.Forms.Views.FrmSearchResult)frm).ArlResultList = resultList;
                        ((Pbdms.Forms.Views.FrmSearchResult)frm).SearchObject = searchObject;
                        ((Pbdms.Forms.Views.FrmSearchResult)frm).reload();
                        frm.Activate();
                        alreadyExisted = true;
                        break;
                    }
                }
                if (!alreadyExisted)
                {
                    Pbdms.Forms.Views.FrmSearchResult frmSearchResult = new Pbdms.Forms.Views.FrmSearchResult(resultList, searchObject);
                    frmSearchResult.MdiParent = this.MdiParent;
                    frmSearchResult.WindowState = FormWindowState.Normal;
                    frmSearchResult.Show();
                }
            }
            else
                return;
        }

        /// <summary>
        /// read bibTexes
        /// </summary>
        /// <returns></returns>
        private ArrayList readBibTexes()
        {
            ArrayList arlBibTexes = new ArrayList();
            for (int i = 1; i <= 10; i++)
            {
                //each bibtex value go along with a pair of dropdownlist and text box
                ComboBox ddl = (ComboBox)(this.Controls.Find("ddl" + i, true)[0]);
                TextBox tb = (TextBox)(this.Controls.Find("tb" + i, true)[0]);
                if (ddl.SelectedItem != null && !tb.Text.Trim().Equals("") && !tb.Text.Trim().Equals("Not in use"))
                {
                    Pbdms.Common.DataObject.BibTexStruct bts = new Pbdms.Common.DataObject.BibTexStruct(ddl.SelectedItem.ToString(), tb.Text.Trim());
                    arlBibTexes.Add(bts);
                }
            }
            return arlBibTexes;
        }

        /// <summary>
        /// read and return a list of tags from the textbox tbTags
        /// </summary>
        /// <returns></returns>
        private ArrayList readTag()
        {
            if (tbTag.Text.Trim().Length > 0)
            {
                String[] tags = tbTag.Text.Trim().Split(',');
                ArrayList tagsReturn = new ArrayList();
                for (int i = 0; i < tags.Length; i++)
                    tagsReturn.Add(tags[i]);
                return tagsReturn;
            }
            return null;

           
        }

        /// <summary>
        /// return false if there is some error in the input
        /// </summary>
        /// <returns></returns>
        private bool validateInput()
        {            
            //check min and max file's size if they are not in double format
            if (chkBHasFile.Checked)            
            {
                Double min =0.0 ,max=0.0;
                bool test = (Double.TryParse(tbMinFileSize.Text, out min) && Double.TryParse(tbMaxFileSize.Text,out max));
                if (!test)   //test doesn't pass
                {
                    Common.Global.showMsgOneButton("Please enter a number into the minimum and maximum file's size", 'I');
                    return false;
                }
                    
                else if (max > 100000)  //if file's size is larger than 100,000KB
                {
                    Common.Global.showMsgOneButton("Max file's size should be at most 100,000 KB", 'W');
                    return false;
                }
            }
                
            //check if there is any uncompleted pair of ddrop downlist - textbox for bibtext specification
            int count = 0;
            for (int i = 1; i <= 10; i++)            {
                //each bibtex value go along with a pair of dropdownlist and text box
                ComboBox ddl = (ComboBox)(this.Controls.Find("ddl" + i, true)[0]);
                TextBox tb = (TextBox)(this.Controls.Find("tb" + i, true)[0]);
                //check to see this pair of ddl and tb provide valid input, if not -> ignore 
                int testValue = testBib(ddl, tb);
                if (testValue == -1)
                    return false;
                else if(testValue==0)
                    count++;
            }
            //if (count == 10) //if none of the bib tex specification is specified.
            //{
            //    Common.Global.showMsgOneButton("Please specify at least one bibTex attribute", 'I');
            //    return false;
            //}
            return true;
        }

        /// <summary>
        /// validate a pair of dropdownlist and text box provide valid bibTex
        /// </summary>
        /// <param name="ddl"></param>
        /// <param name="tb"></param>
        /// <returns>-1 if the structure of the bibTex is not correct, 0 if both ddl and textbox are empty
        /// and 1 otherwise</returns>
        private int testBib(ComboBox ddl, TextBox tb)
        {
            if (ddl.SelectedItem == null)
            {
                if (!tb.Text.Equals(""))
                {
                    Common.Global.showMsgOneButton("Please specify the attribute's name", 'I');
                    ddl.Focus();
                    return -1;
                }
                return 0;
            }
            else
            {
                if (tb.Text.Equals(""))
                    return 0;
                else return 1;
            }
        }

        /// <summary>
        /// enable, disable 2 textboxes: minimum & maximum file size
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkBHasFile_CheckedChanged(object sender, EventArgs e)
        {
            //if chkbox is checked, enable the two textboxes
            if (chkBHasFile.Checked)
            {
                tbMinFileSize.Enabled = true;
                tbMaxFileSize.Enabled = true;
            }
            else
            {
                tbMinFileSize.Enabled = false;
                tbMaxFileSize.Enabled = false;
            }
            
        }

        /// <summary>
        /// reset to initial values (blank)
        /// </summary>
        public void clearSearchCriteria()
        {
            rbLocal.Checked = true;
            tbTag.Text = "";
            ddlCategory.SelectedIndex = 0;
            chkbComment.Checked = false;
            chkBHasFile.Checked = false;
            tbMinFileSize.Text = "0.0";
            tbMaxFileSize.Text = "100000.0";
            for (int i = 1; i <= 10; i++)
            {
                //each bibtex value go along with a pair of dropdownlist and text box
                ComboBox ddl = (ComboBox)(this.Controls.Find("ddl" + i, true)[0]);
                TextBox tb = (TextBox)(this.Controls.Find("tb" + i, true)[0]);
                ddl.SelectedItem = null;
                tb.Text = "";
            }
        }

        /// <summary>
        /// rest the form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnReset_Click(object sender, EventArgs e)
        {
            this.clearSearchCriteria();
        }

        private void mtbRating_TextChanged(object sender, EventArgs e)
        {
            string newRatingValue = normalizeMtbRating(mtbRating.Text);
            if (!newRatingValue.Equals("0.0") && Double.Parse(newRatingValue) > 5)
            {
                Common.Global.showMsgOneButton("Invalid value! Rating must be in between 0 and 5", 'W');
                mtbRating.ResetText();
            }
        }

        /// <summary>
        /// normalize the text in the masked text box for rating of item to be in friendly number format
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private String normalizeMtbRating(String s)
        {
            String[] ar = s.Split('.');
            String sReturn = "";
            if (ar[0].Equals(" "))
                sReturn = "0";
            else
                sReturn = ar[0];

            if (!ar[1].Equals(""))
                sReturn += "." + ar[1];
            return sReturn;
        }
    }
}